/**  
* @Title: StockTask.java 
* @Description:
* @Copyright: Copyright (c) 2018
* @Company:http://www.sinocon.cn
* @author: Su.Yuanlin  
* @date 2019年1月9日  
* @QQ 314078331  
* @Like 流水落花春去也，天上人间
*/
package com.mtons.mblog.quartz.task;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.mtons.mblog.modules.entity.Stock;
import com.mtons.mblog.modules.entity.StockAttr;
import com.mtons.mblog.modules.entity.StockHistory;
import com.mtons.mblog.modules.service.StockService;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
 * @Title: StockTask
 * @Description:
 * @author:Su.Yuanlin
 * @date 2019年1月9日
 */
@Component
@Configurable
@EnableScheduling
public class StockTask implements ApplicationRunner {

	@Autowired
	private StockService stockService;
	
	final static String financeUrl = "http://hq.sinajs.cn/list=";
	// 获得sh600900当日的分价表
	final static String finance_fs_url = "http://market.finance.sina.com.cn/pricehis.php?symbol=sh600900&startdate=2019-03-05&enddate=2019-03-07";

	// 每1分钟执行一次
	@Scheduled(cron = "0 35 15 * * ? ")
	public void reportCurrentByCron() throws InterruptedException, ParseException {
		System.out.println("开始执行任务,预计耗时34分钟，现在时间是： " + dateFormat().format(new Date()));
		DateFormat format1 = new SimpleDateFormat("yyyy/MM/dd");
		Date bdate = format1.parse(DateUtil.today());
		Calendar cal = Calendar.getInstance();
		cal.setTime(bdate);
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			System.out.println("今天是法定节假日哦，大A股不开门....");
		} else {
			execute();
		}

		System.out.println("任务执行完毕，现在时间是： " + dateFormat().format(new Date()));
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("程序启动开始执行任务,预计耗时10分钟，现在时间是： " + dateFormat().format(new Date()));
		// execute();
		System.out.println("启动任务执行完毕，现在时间是： " + dateFormat().format(new Date()));
	}

	private SimpleDateFormat dateFormat() {
		return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	}

	public void execute() throws InterruptedException {
		Map<String, Object> stockCode = this.getStockCode("http://quote.eastmoney.com/stock_list.html");
		this.saveStockInfo(stockCode);
	}

	/**
	 * 获取股票代码
	 * 
	 * @Title: getStockCode
	 * @Description:
	 * @param url
	 * @return
	 */
	public Map<String, Object> getStockCode(String url) {
		String listContent = HttpUtil.get(url);
		// 使用正则获取所有标题
		List<String> titles = ReUtil.findAll("<li>(.*?)</li>", listContent, 1);
		Map<String, Object> stockMap = new HashMap<String, Object>();
		for (String title : titles) {
			// <a target="_blank"
			// href="http://quote.eastmoney.com/sh600009.html">上海机场(600009)</a>
			if (title.startsWith("<a target=\"_blank\" href=\"http://quote.eastmoney.com")) {
				String stockCode = title.substring(title.indexOf("(") + 1, title.lastIndexOf(")"));
				title = title.substring(0, title.indexOf(">"));
				String stockValue = title.substring(title.lastIndexOf("s"), title.lastIndexOf("."));
				stockMap.put(stockCode, stockValue);
			}
		}
		return stockMap;
	}

	/**
	 * 封装成javabean
	 * 
	 * @Title: updateStock
	 * @Description:
	 * @param listContent
	 * @return
	 */
	public static Stock buildStockInfoByStrJson(String listContent) {
		Stock m = null;
		try {
			JSONObject jsonObject = JSONUtil.parseObj(listContent);
			String msgStatus = jsonObject.get("status_msg").toString();
			if ("ok".equals(msgStatus)) {

				JSONObject parseObj = JSONUtil.parseObj(jsonObject.get("data"));
				Object object = parseObj.get("stockcode");
				if (ObjectUtils.isEmpty(object))
					return m;

				Object popularity = parseObj.get("popularity") + "";
				if (ObjectUtils.isEmpty(popularity) || "--".equals(popularity) || "null".equals(popularity))
					popularity = 8888;
				int parseInt = 0;
				try {
					parseInt = Integer.parseInt(popularity + "");
				} catch (Exception e) {
					parseInt = 8888;
					e.printStackTrace();
				}

				m = new Stock();
				m.setStockcode(parseObj.get("stockcode") + "");
				m.setStockname(parseObj.get("stockname") + "");
				m.setPopularity(parseInt);
				m.setCostavg(parseObj.get("cost_avg") + "");

				JSONObject distribution = JSONUtil.parseObj(parseObj.get("distribution"));
				m.setZcw(distribution.get("zcw") + "");
				m.setYlw(distribution.get("ylw") + "");
				m.setJetondesc(distribution.getStr("desc"));

				JSONObject investData = JSONUtil.parseObj(parseObj.get("invest_data"));
				m.setInvestdesc(investData.get("desc") + "");

				JSONObject popularityData = JSONUtil.parseObj(parseObj.get("popularity_data"));
				m.setPopularitydesc(popularityData.get("desc") + "");
				m.setUpdatetime(new Date());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return m;
	}

	public static Stock supplementStock(Stock stock, String addressStock) {
		String string = HttpUtil.get(financeUrl + addressStock);
		String[] split = string.split("=")[1].split(",");
		if (split.length > 3)
			stock.setPrice(split[3]);
		return stock;
	}

	/**
	 * 获取股票信息并且过滤掉已经更新的数据
	 * 
	 * @Title: getStockInfo
	 * @Description:
	 * @param stockCode
	 * @return
	 * @throws ParseException
	 */
	final String ex = "ex";

	private void saveStockInfo(Map<String, Object> stockCode) throws InterruptedException {
		// 获取今天需要更新的数据
		Map<String, Object> existStock = stockFilter();

		String exceptionStock = "";
		try {
			Iterator<String> entries = stockCode.keySet().iterator();
			while (entries.hasNext()) {

				String key = entries.next();

				// 过滤掉今天已经更新的数据
				if (existStock.containsKey(key))
					continue;

				// 不要基金股票
				if (fundFilter(key))
					continue;

				if (exceptionStock.endsWith(ex)) {// 跳出出错的记录
					exceptionStock = "";
					continue;
				}

				exceptionStock = key;

				// 获取财富密码基本信息，请求完毕后休眠1秒，防止被禁IP
				String url = "http://basic.10jqka.com.cn/api/stockph/stockAttention.php?code=" + key;
				String string = HttpUtil.get(url);
				Thread.sleep(1000 * 1);

				// 构建财富密码基本信息
				Stock stock = buildStockInfoByStrJson(string);

				if (ObjectUtil.isNull(stock))
					continue;

				// 获取财富代码收盘价格
				stock = supplementStock(stock, stockCode.get(key).toString());

				// 保存历史价格
				this.saveHistoryPrice(stock);

				// 保存财富密码
				int cnt = this.saveOrUpdateStockInfo(stock);

				// 保存更新记录
				if (cnt > 0) {
					StockAttr t = new StockAttr(stock.getStockcode(), new Date());
					try {
						this.stockService.saveUpdatedStock(t);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("程序暂停1分钟后继续运行，代码----》" + exceptionStock + "错误");
			exceptionStock = ex;
			Thread.sleep(1000 * 60 * 1);
			System.out.println("程序异常后重新启动成功，即将开始业务");
			saveStockInfo(stockCode);
		}

	}

	/**
	 * 过滤掉已经更新的数据
	 * 
	 * @Title: stockFilter
	 * @Description:
	 * @return
	 * 
	 */
	private Map<String, Object> stockFilter() {
		List<StockAttr> listUpdatedStock = this.stockService
				.listStockAttrByUpdateTime(DateUtil.parse(DateUtil.today(), "yyyy-MM-dd"));
		Map<String, Object> existStock = new HashMap<String, Object>();
		for (int i = 0; i < listUpdatedStock.size(); i++) {
			StockAttr tUpdateStock = listUpdatedStock.get(i);
			existStock.put(tUpdateStock.getStockcode(), tUpdateStock.getUpdatetime());
		}
		return existStock;
	}

	/**
	 * 过滤掉基金
	 * 
	 * @Title: fundFilter
	 * @Description:
	 * @param key
	 * @return
	 */
	private boolean fundFilter(String key) {
		if (key.startsWith("15") || key.startsWith("16") || key.startsWith("18") || key.startsWith("20")
				|| key.startsWith("50") || key.startsWith("51") || key.startsWith("58") || key.startsWith("90")) {
			return true;
		}
		return false;
	}

	/**
	 * 保存财富密码
	 * 
	 * @Title: saveOrUpdateStockInfo
	 * @Description:
	 * @param t
	 * @return
	 */
	private int saveOrUpdateStockInfo(Stock t) {
		try {
			this.stockService.save(t);
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
		return 1;
	}

	/**
	 * 保存历史价格
	 * 
	 * @Title: saveHistoryPrice
	 * @Description:
	 * @param t
	 * @return
	 */
	private int saveHistoryPrice(Stock t) {
		List<StockHistory> ls = new ArrayList<>();
		StockHistory sh = new StockHistory();
		sh.setPrice(t.getPrice());
		sh.setStockcode(t.getStockcode());
		sh.setUpdatetime(DateUtil.today());
		sh.setStockname(t.getStockname());
		sh.setUpdatetimeStr(DateUtil.format(new Date(), "MM-dd"));
		sh.setStockid(t.getStockcode() + sh.getUpdatetime());
		sh.setCreatetime(DateUtil.today());
		sh.setQuarter(DateUtil.season(DateUtil.parse(DateUtil.today())));
		ls.add(sh);
		return this.stockService.saveHistoryPrice(ls);
	}

	/**
	 * 过滤掉html标记
	 * 
	 * @Title: replacehtml
	 * @Description:
	 * @param htmlStr
	 * @return
	 */
	public static String replacehtml(String htmlStr) {
		String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式
		String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式
		String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式

		Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
		Matcher m_script = p_script.matcher(htmlStr);
		htmlStr = m_script.replaceAll(""); // 过滤script标签

		Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
		Matcher m_style = p_style.matcher(htmlStr);
		htmlStr = m_style.replaceAll(""); // 过滤style标签

		Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
		Matcher m_html = p_html.matcher(htmlStr);
		htmlStr = m_html.replaceAll(""); // 过滤html标签

		return htmlStr.trim(); // 返回文本字符串
	}
}
